简单快速的对角矩形切片。
看到其他答案后,我发现它们都有点过于复杂了。以下方法比接受的答案快上一个数量级,不需要任何复杂的数据结构、迭代器或生成死亡内存和不必要的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) {
} else if (x < y) {
} else {
}
如果您想改变对角线的方向,只需反转其中一个法线
x = 1 - x;
if (x > y) {
} else if (x < y) {
} else {
}
拆分并使用%运算符
其余的问题只是把网格拆分成(R/2)乘以(H/2)个单元,每个六边形覆盖4列和2行。每3个中的第1列将有对角线,其中每第二列具有翻转的对角线。第4、5和6个列中的每一列都将向下移动一行。通过使用%运算符,您可以非常快速地确定所在的六边形单元格。使用上述对角线拆分方法使数学计算变得简单且快速。
另外一个注意点是,返回参数retPos是可选的。如果按以下方式调用函数,则需要返回此参数:
var retPos;
mainLoop(){
retPos = getHex(mouse.x, mouse.y, retPos);
}
代码不会产生GC压力,进一步提高了速度。
像素到十六进制坐标
从问题图返回十六进制单元格x
,y
位置。请注意,此函数仅适用于范围0 <= x
,0 <= y
,如果需要负坐标,则从输入中减去最小负像素x、y坐标。
var r = 50;
var w = r * 2;
var h = Math.sqrt(3) * r;
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) {
xa = (x % r2) / r2;
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;
}
十六进制转像素
还有一个辅助函数,根据单元格坐标绘制单元格。
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){
ctx.fillStyle = fStyle
ctx.fill();
}
if (sStyle !== undefined ){
ctx.strokeStyle = sStyle
ctx.stroke();
}
}
R*Math.cos(Math.PI/6);
,每60+30度最大值为-> R。因此可能是类似于d <= Math.sin(angle * Math.PI * 6) * (R-R*Math.cos(Math.PI/6)) + R*Math.cos(Math.PI/6)
这样的东西。虽然我现在不能确定,在这个晚上的时间里。 - Redu角度
和距离d
,并且d
必须小于根据角度计算出的数字。我明天会检查。 - Redu