六边形算法:
我把六边形铺满的分布图进行了切分,切分为矩形,每个矩形中有一个六边形、4个三角形、两个小长方形,依次计算。边界判断上,采用主流的MP>MN的方式(M为上边界对称点,N为与六边形的交点,p为要判断的点,如下图)。
实际效果(双色对比):
拾取效果:
代码:
/// <summary>
/// 根据参数获得六边形索引
/// </summary>
/// <param name="width">页面宽度</param>
/// <param name="height">页面长度</param>
/// <param name="r">六边形边长</param>
/// <param name="thickness">六边形上下拓扑半间距</param>
/// <param name="flat">扁平化程度(由于计算过程中,thickness在侧向拓扑中作用减小,故增加了这个系数)</param>
/// <param name="x">横坐标</param>
/// <param name="y">纵坐标</param>
/// <param name="transparent">透明度设置,一般位置为正常值;如果是六边形边界位置的过渡色,减半</param>
/// <returns></returns>
public static int[] GetHexGridIndex(int width, int height, int r, int thickness, int flat, int x, int y, ref byte transparent)
{
//中心点索引(长方形中的六边形的索引)
int indexX = (x / ) / r * ;
int indexY = (int)((int)(y / Math.Sqrt()) / r + indexX / ); //中心点坐标
int centerX = r + (int)(1.5 * r * indexX);
int centerY = (int)(Math.Sqrt() * 0.5 * r * ( + * indexY - indexX)); //位于六边外框之外
if (x > (centerX + r))
{
if (y > centerY + thickness)//右下
{
indexX++;
indexY++;
}
else if (y < centerY - thickness)//右上
{
indexX++;
}
else//中间部分以及外延部分
{
indexX = -;
indexY = -;
}
}
else//六边外框之内
{
if (x > centerX + r / )//右半区
{
if (y > centerY)//右下
{
var M = Math.Sqrt() / * r + centerY;//上边界点
var N = (centerX + r - x) * Math.Sqrt() + centerY;//六边形边界点
var MP = (int)(M - y);
var MN = (int)(M - N);
if (MP > (MN + thickness * flat))//六边形内部
{
//索引不变
}
else if (MP < (MN - thickness * flat))//六边形外部
{
indexX++;
indexY++;
}
else//交界区
{
if (MP == MN + thickness * flat)//紧靠内部
{
transparent = (byte)(transparent / );
////去除右侧尖尖
if (x == centerX + r - thickness)
{
indexX = -;
indexY = -;
}
}
else if (MP == MN - thickness * flat)//紧靠外部
{
indexX++;
indexY++;
transparent = (byte)(transparent / );
}
else//中间区
{
indexX = -;
indexY = -;
}
}
}
else//右上
{
var M = centerY - Math.Sqrt() / * r;
var N = centerY - (centerX + r - x) * Math.Sqrt();
var MP = (int)(y - M);
var MN = (int)(N - M);
if (MP > (MN + thickness * flat))//内部
{
////索引不变,但是要去除右侧尖尖
if (x == centerX + r - thickness)
{
indexX = -;
indexY = -;
}
}
else if (MP < (MN - thickness * flat))//外部,索引单变
{
indexX++;
}
else
{
if (MP == MN + thickness * flat)//里侧
{
transparent = (byte)(transparent / );
if (x == centerX + r - thickness - )////去除右侧尖尖
{
indexX = -;
indexY = -;
}
}
else if (MP == MN - thickness * flat)//外侧
{
indexX++;
transparent = (byte)(transparent / );
}
else
{
indexX = -;
indexY = -;
}
}
}
}
else if (x < centerX - r / )//左半区
{
if (y < centerY)//左上
{
var M = centerY - Math.Sqrt() / * r;
var N = centerY + (centerX - r - x) * Math.Sqrt();
var MP = (int)(y - M);
var MN = (int)(N - M);
if (MP > (MN + thickness * flat))
{
//索引不变
}
else if (MP < (MN - thickness * flat))//索引单变
{
indexX--;
indexY--;
}
else
{
if (MP == MN + thickness * flat)//里侧
{
transparent = (byte)(transparent / );
if (x == centerX - r + thickness + )
{
indexX = -;
indexY = -;
}
}
else if (MP == MN - thickness * flat)//外侧
{
indexX--;
indexY--;
transparent = (byte)(transparent / );
}
else
{
indexX = -;
indexY = -;
}
}
}
else//左下
{
var M = centerY + Math.Sqrt() / * r;
var N = centerY - (centerX - r - x) * Math.Sqrt();
var MP = (int)(M - y);
var MN = (int)(M - N);
if (MP > (MN + thickness * flat))//内部
{
if (x == centerX - r + thickness + )//索引不变,但是要清除突兀部分
{
indexX = -;
indexY = -;
}
}
else if (MP < (MN - thickness * flat))//索引单变
{
indexX--;
}
else//隔离带
{
if (MP == MN + thickness * flat)//里侧
{
transparent = (byte)(transparent / );
if (x < centerX - r + thickness * flat - )
{
indexX = -;
indexY = -;
}
}
else if (MP == MN - thickness * flat)//外侧
{
indexX--;
transparent = (byte)(transparent / );
}
else
{
indexX = -;
indexY = -;
}
}
}
}
else//六边形竖条内部
{
var step = (int)Math.Round(Math.Sqrt() * r);
var remainder = y % step; if (remainder <= thickness)//上缓冲
{
indexX = -;
indexY = -;
}
else if (step - remainder - <= thickness)//下缓冲
{
indexX = -;
indexY = -;
} if ((remainder - == thickness) || (step - remainder - == thickness))//六边形上下四圆角控制(分为上下半身)
{
//去除四点
var first = (int)(centerX - r / );
var second = (int)Math.Ceiling((double)centerX - r / );
var third = (int)(centerX + r / );
var fourth = (int)Math.Ceiling((double)centerX + r / ); if (x == first || x == second || x == third || x == fourth)
{
indexX = -;
indexY = -;
}
}
}
} //right超出界面的设置
var rightIndex = Math.Floor(Convert.ToDouble(width - r - r) / ( * Convert.ToDouble(r) / ));
bool xx = indexX > rightIndex;
if (indexX > rightIndex)
{
indexX = -;
indexY = -;
} //bottom超出界面的设置
var bottomIndex = Math.Floor(height / (r * Math.Sqrt())) - ;
//基础位置为(0,bottomIndex+1)
if (indexY > bottomIndex)//&&((indexX-0)%(indexY-(bottomIndex+1))==0))
{
//下分三种情况,第一种是首索引
var isOrNotFirstIndex = indexX == && (indexY == bottomIndex + );
//与首索引同行位置的索引
var isOrNotFirstLineIndex = indexX == (indexY - (bottomIndex + )) * ;
//侧移索引
var isOrNotSideSwayIndex = (indexX + ) == (indexY - (bottomIndex + )) * ; if (isOrNotFirstIndex || isOrNotFirstLineIndex || isOrNotSideSwayIndex)
{
indexX = -;
indexY = -;
}
} return new int[] { indexX, indexY };
}
六边形算法