简单快速的对角矩形切片。
查看其他答案,我发现他们的问题有点过于复杂了。以下是比接受的答案快一个数量级,并且不需要任何复杂的数据结构、迭代器或生成死内存和不需要的 GC 命中。它返回 R、H、S 或 W 的任何相关集的十六进制单元格行和列。示例使用 R = 50。
如果矩形被对角分割,部分问题是找到一个点在矩形的哪一边。这是一个非常简单的计算,通过对要测试的点的位置进行归一化来完成。
对角切割任何矩形
例如一个宽度为 w 且高度为 h 的矩形从左上角到右下角分割。查找一个点是左还是右。假设矩形的左上角在 rx,ry
var x = ?;
var y = ?;
x = ((x - rx) % w) / w;
y = ((y - ry) % h) / h;
if (x > y) {
// point is in the upper right triangle
} else if (x < y) {
// point is in lower left triangle
} else {
// point is on the diagonal
}
如果你想改变对角线的方向,那么只需反转一个法线
x = 1 - x; // invert x or y to change the direction the rectangle is split
if (x > y) {
// point is in the upper left triangle
} else if (x < y) {
// point is in lower right triangle
} else {
// point is on the diagonal
}
拆分成子单元格并使用%
剩下的问题只是将网格分成 (R / 2) x (H / 2) 单元格,每个十六进制宽度覆盖 4 列和 2 行。 3 列中的每一列都有对角线。这些列的每一秒都有对角线翻转。对于每 6 列中的第 4、5 和 6 列,该行向下移动一个单元格。通过使用 % 您可以非常快速地确定您所在的十六进制单元格。使用上面的对角线分割方法可以让数学变得简单快捷。
还有一点。返回参数 retPos 是可选的。如果你调用函数如下
var retPos;
mainLoop(){
retPos = getHex(mouse.x, mouse.y, retPos);
}
代码不会导致GC命中,进一步提高速度。
像素到十六进制坐标
从问题图返回十六进制单元格x,y pos。请注意,此函数仅适用于0 <= x、0 <= y 范围内,如果您需要负坐标,请从输入中减去最小负像素 x,y 坐标
// the values as set out in the question image
var r = 50;
var w = r * 2;
var h = Math.sqrt(3) * r;
// returns the hex grid x,y position in the object retPos.
// retPos is created if not supplied;
// argument x,y is pixel coordinate (for mouse or what ever you are looking to find)
function getHex (x, y, retPos){
if(retPos === undefined){
retPos = {};
}
var xa, ya, xpos, xx, yy, r2, h2;
r2 = r / 2;
h2 = h / 2;
xx = Math.floor(x / r2);
yy = Math.floor(y / h2);
xpos = Math.floor(xx / 3);
xx %= 6;
if (xx % 3 === 0) { // column with diagonals
xa = (x % r2) / r2; // to find the diagonals
ya = (y % h2) / h2;
if (yy % 2===0) {
ya = 1 - ya;
}
if (xx === 3) {
xa = 1 - xa;
}
if (xa > ya) {
retPos.x = xpos + (xx === 3 ? -1 : 0);
retPos.y = Math.floor(yy / 2);
return retPos;
}
retPos.x = xpos + (xx === 0 ? -1 : 0);
retPos.y = Math.floor((yy + 1) / 2);
return retPos;
}
if (xx < 3) {
retPos.x = xpos + (xx === 3 ? -1 : 0);
retPos.y = Math.floor(yy / 2);
return retPos;
}
retPos.x = xpos + (xx === 0 ? -1 : 0);
retPos.y = Math.floor((yy + 1) / 2);
return retPos;
}
十六进制到像素
还有一个辅助函数,在给定单元格坐标的情况下绘制一个单元格。
// Helper function draws a cell at hex coordinates cellx,celly
// fStyle is fill style
// sStyle is strock style;
// fStyle and sStyle are optional. Fill or stroke will only be made if style given
function drawCell1(cellPos, fStyle, sStyle){
var cell = [1,0, 3,0, 4,1, 3,2, 1,2, 0,1];
var r2 = r / 2;
var h2 = h / 2;
function drawCell(x, y){
var i = 0;
ctx.beginPath();
ctx.moveTo((x + cell[i++]) * r2, (y + cell[i++]) * h2)
while (i < cell.length) {
ctx.lineTo((x + cell[i++]) * r2, (y + cell[i++]) * h2)
}
ctx.closePath();
}
ctx.lineWidth = 2;
var cx = Math.floor(cellPos.x * 3);
var cy = Math.floor(cellPos.y * 2);
if(cellPos.x % 2 === 1){
cy -= 1;
}
drawCell(cx, cy);
if (fStyle !== undefined && fStyle !== null){ // fill hex is fStyle given
ctx.fillStyle = fStyle
ctx.fill();
}
if (sStyle !== undefined ){ // stroke hex is fStyle given
ctx.strokeStyle = sStyle
ctx.stroke();
}
}