Подтвердить что ты не робот

Заполнение круга шестиугольниками (разный подход)

Как мой предыдущий подход не работает, и решение будет довольно сложным, я решил попробовать другой подход, который может быть немного проще.

На этот раз, прежде чем код рисует любой шестиугольник, он должен определить, сколько строк и столбцов может поместиться в заданный круг, и на основе этого результата он затем начнет рисовать все шестиугольники.

Пока это какая-то работа, но, как и в моем предыдущем подходе, бывают случаи, когда гексы перекрываются или оставляют большой зазор в нижней части круга.

Еще одна проблема заключается в том, как форматировать эти шестиугольники в сетку?

Заметьте, что под холстом имеется небольшой слайдер, который позволяет увеличить/уменьшить радиус окружности и перерисовать шестиугольники.

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 circle = {
	r: 120, /// radius 
	pos: {
		x: (canvas_width / 2),
		y: (canvas_height / 2)
	}
}

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

var hex_w = hexagon.r * 2;
var hex_h = Math.floor( Math.sqrt(3) * hexagon.r );
var hex_s =  (3/2) * hexagon.r;

fill_CircleWithHex( circle );

function fill_CircleWithHex(circle){
	drawCircle( circle );
	
	var c_h = circle.r * 2; /// circle height ////
	var c_w = c_h; //// circle width /////
	
	var max_hex_H = Math.round( c_h /  hex_h );
	
	var row_sizes = []
	for(var row= 0; row< max_hex_H; row++){
		
		var d = circle.r - ( row* hex_h);  //// distance from circle center to the row chord ////
		var c = 2 * (Math.sqrt((circle.r*circle.r) - (d * d))); ///  length of the row chord ////
		var row_length = Math.floor(c / (hexagon.r * 3));
		row_sizes.push( row_length  )
	}
	
	console.log("circle_r : "+circle.r);
	console.log("hex_r : "+hexagon.r);
	console.log("max_hex_H : "+max_hex_H);
	console.log("max_hex_W : ", row_sizes)

	for(var row = 0; row < row_sizes.length; row++){
		var max_hex_W = row_sizes[row];
		
		var x_offset = Math.floor((c_w - (max_hex_W * hex_w)) / 2);
		
		for(var col = 1; col < max_hex_W; col++){
			hexagon.pos.x =  (col * hex_w) + (circle.pos.x - circle.r) + x_offset ;
			hexagon.pos.y =  (row * hex_h) + (circle.pos.y - circle.r);
			ctx.fillText(row+""+col, hexagon.pos.x - 6, hexagon.pos.y+4);
			drawHexagon(hexagon)
		}
	}
}

function drawHexagon(hex){
	var angle_deg, angle_rad, cor_x, cor_y;
	ctx.beginPath();
	for(var c=0; c <= 5; c++){
		angle_deg = 60 * c;
		angle_rad = (Math.PI / 180) * angle_deg;
		cor_x = hex.r * Math.cos(angle_rad); //// corner_x ///
		cor_y = hex.r* Math.sin(angle_rad); //// corner_y ///
		if(c === 0){
			ctx.moveTo(hex.pos.x+ cor_x, hex.pos.y+cor_y);
		}else{
			ctx.lineTo(hex.pos.x+cor_x, hex.pos.y+cor_y);
		}
	}
	ctx.closePath();
	ctx.stroke();
}

function drawCircle( circle ){
	ctx.beginPath();
	ctx.arc(circle.pos.x, circle.pos.y, circle.r, 0, 2 * Math.PI);
	ctx.stroke();
}


  $(function() {
    $( "#slider" ).slider({
		max: 200,
		min:0,
		value:100,
		create: function( event, ui ) {
			$("#value").html( $(this).slider('value') );
		},
		change: function( event, ui ) {
			$("#value").html(ui.value);
		},
		slide: function( event, ui){
			$("#value").html(ui.value);
			circle.r = ui.value;
			ctx.clearRect(0,0, canvas_width, canvas_height);
			fill_CircleWithHex(circle);
		}
	});
  });
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<link href="#" onclick="location.href='https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.11.4/jquery-ui.min.css'; return false;" rel="stylesheet"/>
<script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/jquery-ui.min.js"></script>

<canvas id="myCanvas" width="350" height="250" style="border:1px solid #d3d3d3;"> </canvas>
<div style="width: 200px; height: 40px;">
	<div id="slider" style="position:relative; width: 150px; top: 4px;float: left;"></div> <div id="value" style="float: left;"> 0 </div>
</div>
4b9b3361

Ответ 1

Следующее решение проблемы упаковки для регулярной сотовой структуры с центром в средней точке круга. Регулярные средства:

  • множество всех шестиугольников симметрично при 60 градусах вращения вокруг центра окружности.

Координаты отдельных шестиугольников представляют собой порядковый номер шестиугольной оболочки, противодействующей от центра, и порядковый номер по часовой стрелке, начинающийся в полдень.

По мере расширения круга новые шестиугольные оболочки не обязательно заполняются в целом. Хотя степень свободы заполнения внешней оболочки частично дает улучшенное решение, она по-прежнему не оптимальна. Расслабление регулярности вращательных симметрий по другим углам, чем 60 градусов (а именно, 120 и 180 градусов), позволит обеспечить более высокий охват внутренней окружности.

Я рассмотрю математику за тем, что для следующей ревизии этого кода (и, возможно, найти теорему, чтобы доказать, что вращательная симметрия вокруг окружности - это необходимое условие оптимальности).

var c_el;
var ctx;
var canvas_width;
var canvas_height;
var circle;
var hexagon;
var hex_w;
var hex_h;
var hex_s;
var delta;

function drawHexagonAt ( po_ctr_hex, pn_circle, pn_sector ) {
    var cur
      ;
      
    cur = { x: po_ctr_hex.x - 0.5 * hexagon.r, y: po_ctr_hex.y - delta };
    
    ctx.beginPath();
    ctx.moveTo(cur.x, cur.y);
    cur.x = cur.x + hexagon.r;
    cur.y = cur.y;
    ctx.lineTo(cur.x, cur.y);
    cur.x = cur.x + hexagon.r / 2;
    cur.y = cur.y + delta;
    ctx.lineTo(cur.x, cur.y);
    cur.x = cur.x - hexagon.r / 2;
    cur.y = cur.y + delta;
    ctx.lineTo(cur.x, cur.y);
    cur.x = cur.x - hexagon.r;
    cur.y = cur.y;
    ctx.lineTo(cur.x, cur.y);
    cur.x = cur.x - hexagon.r / 2;
    cur.y = cur.y - delta;
    ctx.lineTo(cur.x, cur.y);
    cur.x = cur.x + hexagon.r / 2;
    cur.y = cur.y - delta;
    ctx.lineTo(cur.x, cur.y);
	ctx.closePath();
	ctx.stroke();

    cur.x = cur.x + hexagon.r / 2;
    cur.y = cur.y + delta;
	ctx.fillText(pn_circle + "/" + pn_sector, cur.x-6, cur.y+4);
} // drawHexagonAt

function fill_CircleWithHex(circle){
	drawCircle( circle );
	
	var radacc2;
	var iter    = 0;
	var sector  = 0;
	var i, j;
	var ctr     = { x: circle.pos.x , y: circle.pos.y };
	var cur     = { x: 0            , y: 0 };
	
	delta   = Math.floor(Math.sqrt(3) * 0.5 * hexagon.r);
    radacc2 = hexagon.r * hexagon.r;
	while ( (radacc2 < circle.r * circle.r) ) {
	    cur.x = ctr.x;
	    cur.y = ctr.y - iter * 2 * delta;
	    
	    if (iter === 0) {
	        drawHexagonAt ( cur, 0, 0 );
	    }
	    else {
    	    for ( var i=0; i < 6; i++ ) {
    	        // j-loops -- next honeycomb
    	        sector = 0;
    	        for ( var j=0; j < iter; j++ ) {
    	            cur.x = cur.x + 1.5 * hexagon.r;
    	            cur.y = cur.y + delta;
    	            drawHexagonAt ( cur, iter, sector++ );
    	        }
    	        for ( var j=0; j < iter; j++ ) {
    	            cur.x = cur.x;
    	            cur.y = cur.y + 2 * delta;
    	            drawHexagonAt ( cur, iter, sector++ );
    	        } 
    	        for ( var j=0; j < iter; j++ ) {
    	            cur.x = cur.x - 1.5 * hexagon.r;
    	            cur.y = cur.y + delta;
    	            drawHexagonAt ( cur, iter, sector++ );
    	        } 
    	        for ( var j=0; j < iter; j++ ) {
    	            cur.x = cur.x - 1.5 * hexagon.r;
    	            cur.y = cur.y - delta;
    	            drawHexagonAt ( cur, iter, sector++ );
    	        } 
    	        for ( var j=0; j < iter; j++ ) {
    	            cur.x = cur.x;
    	            cur.y = cur.y - 2 * delta;
    	            drawHexagonAt ( cur, iter, sector++ );
    	        } 
    	        for ( var j=0; j < iter; j++ ) {
    	            cur.x = cur.x + 1.5 * hexagon.r;
    	            cur.y = cur.y - delta;
    	            drawHexagonAt ( cur, iter, sector++ );
    	        }
    	    } // i-loop -- meta-honeycomb
    	} // if -- Iteration 1 vs. n > 1
 	    
 	    // radacc update
 	    iter++;
        radacc2 = ((2*iter + 1) * delta) * ((2*iter + 1) * delta) + hexagon.r * hexagon.r / 4;
    } // while -- komplette Shells
    
    //
    //  Partielle Shells
    //
    var proceed;
    do {
	    cur.x   = ctr.x;
	    cur.y   = ctr.y - iter * 2 * delta;
        proceed = false;

	    for ( var i=0; i < 6; i++ ) {
	        // j-loops -- next honeycomb
	        sector = 0;
	        for ( var j=0; j < iter; j++ ) {
	            cur.x = cur.x + 1.5 * hexagon.r;
	            cur.y = cur.y + delta;
	            sector++
	            if ( Math.sqrt ( ( cur.x - ctr.x) * ( cur.x - ctr.x) + ( cur.y - ctr.y) * ( cur.y - ctr.y) ) + hexagon.r < circle.r ) {
	                drawHexagonAt ( cur, iter, sector );
	                proceed = true;
	            }
	        }
	        for ( var j=0; j < iter; j++ ) {
	            cur.x = cur.x;
	            cur.y = cur.y + 2 * delta;
	            sector++
	            if ( Math.sqrt ( ( cur.x - ctr.x) * ( cur.x - ctr.x) + ( cur.y - ctr.y) * ( cur.y - ctr.y) ) + hexagon.r < circle.r ) {
	                drawHexagonAt ( cur, iter, sector );
	                proceed = true;
	            }
	        } 
	        for ( var j=0; j < iter; j++ ) {
	            cur.x = cur.x - 1.5 * hexagon.r;
	            cur.y = cur.y + delta;
	            sector++
	            if ( Math.sqrt ( ( cur.x - ctr.x) * ( cur.x - ctr.x) + ( cur.y - ctr.y) * ( cur.y - ctr.y) ) + hexagon.r < circle.r ) {
	                drawHexagonAt ( cur, iter, sector );
	                proceed = true;
	            }
	        } 
	        for ( var j=0; j < iter; j++ ) {
	            cur.x = cur.x - 1.5 * hexagon.r;
	            cur.y = cur.y - delta;
	            sector++
	            if ( Math.sqrt ( ( cur.x - ctr.x) * ( cur.x - ctr.x) + ( cur.y - ctr.y) * ( cur.y - ctr.y) ) + hexagon.r < circle.r ) {
	                drawHexagonAt ( cur, iter, sector );
	                proceed = true;
	            }
	        } 
	        for ( var j=0; j < iter; j++ ) {
	            cur.x = cur.x;
	            cur.y = cur.y - 2 * delta;
	            sector++
	            if ( Math.sqrt ( ( cur.x - ctr.x) * ( cur.x - ctr.x) + ( cur.y - ctr.y) * ( cur.y - ctr.y) ) + hexagon.r < circle.r ) {
	                drawHexagonAt ( cur, iter, sector );
	                proceed = true;
	            }
	        } 
	        for ( var j=0; j < iter; j++ ) {
	            cur.x = cur.x + 1.5 * hexagon.r;
	            cur.y = cur.y - delta;
	            sector++
	            if ( Math.sqrt ( ( cur.x - ctr.x) * ( cur.x - ctr.x) + ( cur.y - ctr.y) * ( cur.y - ctr.y) ) + hexagon.r < circle.r ) {
	                drawHexagonAt ( cur, iter, sector );
	                proceed = true;
	            }
	        }
	    } // i-loop -- meta-honeycomb
	    
	    iter++;
    } while (proceed && (iter < 15));       
    
} // fill_CircleWithHex


function drawCircle( circle ){
	ctx.beginPath();
	ctx.arc(circle.pos.x, circle.pos.y, circle.r, 0, 2 * Math.PI);
	ctx.stroke();
}


  $(function() {
    $( "#slider" ).slider({
		max: 200,
		min:0,
		value:100,
		create: function( event, ui ) {
			$("#value").html( $(this).slider('value') );
		},
		change: function( event, ui ) {
			$("#value").html(ui.value);
		},
		slide: function( event, ui){
			$("#value").html(ui.value);
			circle.r = ui.value;
			ctx.clearRect(0,0, canvas_width, canvas_height);
			fill_CircleWithHex(circle);
		}
	});
  });
  
$(document).ready(function () {
    c_el = document.getElementById("myCanvas");
    ctx = c_el.getContext("2d");
    
    canvas_width = c_el.clientWidth;
    canvas_height = c_el.clientHeight;

    circle = {
    	r: 120, /// radius 
    	pos: {
    		x: (canvas_width / 2),
    		y: (canvas_height / 2)
    	}
    };
    
    hexagon = {
    	r: 20,
    	pos:{
    		x: 0,
    		y: 0
    	}
    };
    
    hex_w = hexagon.r * 2;
    hex_h = Math.floor( Math.sqrt(3) * hexagon.r );
    hex_s =  (3/2) * hexagon.r;
    
    fill_CircleWithHex( circle );
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.11.4/jquery-ui.min.css" rel="stylesheet"/>
<script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/jquery-ui.min.js"></script>

<canvas id="myCanvas" width="350" height="250" style="border:1px solid #d3d3d3;"> </canvas>
<div style="width: 200px; height: 40px;">
<div id="slider" style="position:relative; width: 150px; top: 4px;float: left;"></div> <div id="value" style="float: left;"> 0 </div>
</div>

Ответ 2

Проделал некоторое время на вашем коде, чтобы упаковать шестнадцатеричный. Это не идеально, и я уверен, что есть лучший способ сделать это. Проверьте это, если это поможет, или если вы можете исправить гексагон, выходящий из круга [теперь есть проблема с вычислением row_sizes]. Может быть, я могу посмотреть на это снова, когда у меня будет время, или мы можем посмотреть на другие способы сделать это.

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 circle = {
	r: 120, /// radius 
	pos: {
		x: (canvas_width / 2),
		y: (canvas_height / 2)
	}
}

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

var hex_w = hexagon.r * 3; /// added spacing
var hex_h = Math.floor( Math.sqrt(3) * hexagon.r / 2 ); /// added spacing 
var hex_s =  (3/2) * hexagon.r;

var hex_width = 33.4; //based on r = 20

fill_CircleWithHex( circle );

function fill_CircleWithHex(circle){
	drawCircle( circle );
	
	var c_h = circle.r * 2; /// circle height ////
	var c_w = c_h; //// circle width /////

	var max_hex_H = Math.round( c_h /  ( hex_h  ));
	var row_sizes = []
  
	for(var col= 0; col < max_hex_H; col++){
		
		var d = circle.r - ( col * hex_h );  //// distance from circle center to the row chord ////
		var c = 2 * (Math.sqrt((circle.r*circle.r) - (d * d))); ///  length of the row chord ////
		
		row_sizes.push( Math.ceil(c / (hexagon.r * 3)) )
	}

	for(var row = 0; row < row_sizes.length; row++){
		var max_hex_W = row_sizes[row];
    console.log(hex_w);
		var x_offset =  Math.floor((c_w - (max_hex_W * hex_w))) + row%2 * hex_width - hex_width/2; // changed offset to define a zig zag
		
		for(var col = 1; col < max_hex_W; col++){
			hexagon.pos.x =  (col * hex_w) + (circle.pos.x - circle.r) + x_offset ;
			hexagon.pos.y =  (row * 17.3) + (circle.pos.y - circle.r) ;
			ctx.fillText(row+""+col, hexagon.pos.x - 6, hexagon.pos.y+4);
			drawHexagon(hexagon)
		}
	}
}

function drawHexagon(hex){
	var angle_deg, angle_rad, cor_x, cor_y;
	ctx.beginPath();
 
	for(var c=0; c <= 5; c++){
		angle_deg = 60 * c;
		angle_rad = (Math.PI / 180) * angle_deg;
		cor_x = hex.r * Math.cos(angle_rad); //// corner_x ///
		cor_y = hex.r* Math.sin(angle_rad); //// corner_y ///
		if(c === 0){
			ctx.moveTo(hex.pos.x+ cor_x, hex.pos.y+cor_y);
		}else{
			ctx.lineTo(hex.pos.x+cor_x, hex.pos.y+cor_y);
		}
	}
	ctx.closePath();
	ctx.stroke();
}

function drawCircle( circle ){
	ctx.beginPath();
	ctx.arc(circle.pos.x, circle.pos.y, circle.r, 0, 2 * Math.PI);
	ctx.stroke();
}


  $(function() {
    $( "#slider" ).slider({
		max: 200,
		min:0,
		value:100,
		create: function( event, ui ) {
			$("#value").html( $(this).slider('value') );
		},
		change: function( event, ui ) {
			$("#value").html(ui.value);
		},
		slide: function( event, ui){
			$("#value").html(ui.value);
			circle.r = ui.value;
			ctx.clearRect(0,0, canvas_width, canvas_height);
			fill_CircleWithHex(circle);
		}
	});
  });
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.11.4/jquery-ui.min.css" rel="stylesheet"/>
<script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/jquery-ui.min.js"></script>

<canvas id="myCanvas" width="350" height="250" style="border:1px solid #d3d3d3;"> </canvas>
<div style="width: 200px; height: 40px;">
	<div id="slider" style="position:relative; width: 150px; top: 4px;float: left;"></div> <div id="value" style="float: left;"> 0 </div>
</div>

Ответ 3

Короткий ответ: нет простого способа сделать это. У вас слишком много особых случаев. Чтобы проиллюстрировать это, начните просто с 1, 2, 3, 4, 6 и 7 шестиугольников, нарисуйте минимальный круг, который поместится над ними, и отметьте, где заканчивается центр круга.

Как вы можете видеть, центр круга перемещается совсем немного. Он может оказаться в середине шестиугольника, на вершине или перекрестке.

С этого момента он только ухудшается.

Ближайшим я могу найти по этой проблеме эту страницу.

EDIT: вы можете захотеть проверить следующую страницу блога для очень всестороннего лечения шестиугольников в программировании.

http://www.redblobgames.com/grids/hexagons/