转载几个蜂窝小区的数学模型
设计模型:
1、 设计一个XY轴坐标系,1是原点,坐标(0,0)
2、 X轴:49、28、13、4、1、7、19、37、61的六边形中心所在直线(如图),1和7之间的距离是7,对应坐标轴的1个刻度
3、 Y轴:45、25、11、3、1、6、17、34、57 的六边形中心所在直线(如图),同样刻度是1
4、 从内向外都是有一个个圈(Cycle)组成,1是第0圈,2-7是第1圈,8-19是第2圈(见图上有颜色的六边形组成的一个圈)
5、 每个圈都有6条边(除了第0圈只有1个)
6、 第N圈的每条边都有N个六边形(如图:有颜色的六边形组成的第2圈,相同颜色的组成一条边)
7、 第N圈的起点编号是CycStartID(n),结束编号是CycEndID(n),那么有:CycStartID(n)=CycEndID(n-1)+1,CycEndID(n) = CycStartID+6n-1
8、 每个圈的移动顺序是(举例第2圈):7-(Down)-8-(LeftDown)-9-(LeftUp)-10-(LeftUp)-11-(Up)-12-(Up)-13-(RightUp)-14-(RightUp)-15-(RightDown)-16-(RightDown)-17-(Down)-18-(Down)-19
9、 从上述的移动可以看出,第N圈的第一条边(比如第2圈的8,9)的顺序都是:先Down à 循环N-1次LeftDown à 循环N次LeftUP à 循环N次Up à 循环N次RightUp à 循环N次RightDown à 循环N次Down
10、 从图中坐标可以看出,每次移动的坐标变化规律如下:
a) Down=(1,-1),
b) LeftDown=(0,-1),
c) LeftUp=(-1,0),
d) Up=(-1,1),
e) RightUp=(0,1)
f) RightDown=(1,0)
g) Down=(1,-1)
11、 从图中坐标可以看出,在第一、三象限的距离是X或Y的最大值,而第二、四象限的距离是X+Y。因此,如果两个编号的坐标相减(A-B),如果落在第一三象限,则就是(A-B)的X或Y的最大值的绝对值。否则落在第二四象限,就是(A-B)的X和Y的绝对值的和。
思路2:
通过数学归纳,我们可以知道,从第2圈开始,第n圈所拥有的数字个数是6*(n-1),那么,第n圈的最大值是:1+6*(2-1)+6*(3-1)+……+6*(n-1)=3*n*(n-1)+1;第n圈的最小值即第n-1圈的最大值+1。通过上述公式,我们可以知道任意数字所在的圈数n。
观察上图,我们发现每一圈数字组成的图形是一个正六边形, X轴上分别是正六边形的第3个顶点(负值)和第6个顶点,Y轴上分别是六边形的第2个顶点(负值)和第5个顶点,同时第6个顶点也是圈中的最大值。
正六边形的每一条边的长度包含N个数字,从而,我们可以从第6个顶点反向回推各个顶点的值。比如:
第5个顶点的值是:(3*n*(n-1)+1)-(n-1);
第4个顶点的值是:(3*n*(n-1)+1)-(n-1)-(n-1);
…………
通过已知的6个顶点的取值,我们可以获取到当前数字所在哪一条边,从而根据不同的边计算出具体数字所在的二维坐标,从而将蜂窝最短距离的计算转换成二维坐标中两点间距离的计算。
代码展示:
struct XY
{
int x;
int y;
};
// 获取某点的坐标
void GetValueCoordinate(int iValue, XY &strXY)
{
// 坐标原点为(0,0)
if (1 == iValue)
{
strXY.x = 0;
strXY.y = 0;
return;
}
// 1、定位该点所在的圈数
// 第n圈的元素个数:6*(n-1)
// 第n圈的起始元素:3n^2-9n+8
// 第n圈的结束元素:3n^2-3n+1
int n = 1;
while(iValue > (3*n*n-3*n+1))
{
n++;
}
// 2、定位该点所在的边,从而获取到象限信息
// 六边形每条边所含点数为当前圈数n,以圈中最大点数为第6个顶点,那么对应6个顶点数分别是:
// 第6个顶点:3n^2-3n+1
// 第5个顶点:3n^2-3n+1-(n-1)=3n^2-4n+2
// 第4个顶点:3n^2-4n+2-(n-1)=3n^2-5n+3
// 第3个顶点:3n^2-5n+3-(n-1)=3n^2-6n+4
// 第2个顶点:3n^2-6n+4-(n-1)=3n^2-7n+5
// 第1个顶点:3n^2-7n+5-(n-1)=3n^2-8n+6
// X轴上分别是六边形的第3个顶点和第6个顶点
// X轴:49、28、13、4、1、7、19、37、61
// Y轴上分别是六边形的第2个顶点和第5个顶点
// Y轴:45、25、11、3、1、6、17、34、57
// 1、2顶点之间,第4象限
if (((3*n*n-8*n+6) <= iValue) && (iValue < (3*n*n-7*n+5)))
{
// X轴=第2个顶点-点数
strXY.x = (3*n*n-7*n+5)-iValue;
// Y轴固定为圈数-1(负值)
strXY.y = -(n-1);
}
// 2、3顶点之间,第3象限
else if (((3*n*n-7*n+5) <= iValue) && (iValue < (3*n*n-6*n+4)))
{
// X轴=圈数-1-偏移(偏移=第3个顶点-点数)(负值)
strXY.x = -((n-1) - ((3*n*n-6*n+4)-iValue));
// Y轴=圈数-1-偏移(偏移=点数-第2个顶点)(负值)
strXY.y = -((n-1) - (iValue - (3*n*n-7*n+5)));
}
// 3、4顶点之间,第2象限
else if (((3*n*n-6*n+4) <= iValue) && (iValue < (3*n*n-5*n+3)))
{
// X轴固定为圈数-1(负值)
strXY.x = -(n-1);
// Y轴=点数-第3个顶点
strXY.y = iValue - (3*n*n-6*n+4);
}
// 4、5顶点之间,第2象限
else if (((3*n*n-5*n+3) <= iValue) && (iValue < (3*n*n-4*n+2)))
{
// X轴=第5个顶点-点数(负值)
strXY.x = -((3*n*n-4*n+2)-iValue);
// Y轴固定为圈数-1
strXY.y = (n-1);
}
// 5、6顶点之间,第1象限
else if (((3*n*n-4*n+2) <= iValue) && (iValue < (3*n*n-3*n+1)))
{
// X轴=圈数-1-偏移(偏移=第6个顶点-点数)
strXY.x = (n-1) - ((3*n*n-3*n+1)-iValue);
// Y轴=圈数-1-偏移(偏移=点数-第5个顶点)
strXY.y = (n-1) - (iValue - (3*n*n-4*n+2));
}
// 6、1顶点之间,第4象限
else
{
// X轴固定为圈数-1
strXY.x = (n-1);
// 如果是当前圈的结束元素(第6个顶点),Y轴直接赋0值
// 否则,Y轴=点数-第n圈的起始元素+1(负值)
if (iValue == (3*n*n-3*n+1))
{
strXY.y = 0;
}
else
{
strXY.y = -(iValue - (3*n*n-9*n+8) + 1);
}
}
return;
}
思路3
思路4:
数学方法思路:
1)先定义两个坐标系
一个是二维斜坐标,X轴(1,2,9,22,41,...),Y轴(1,7,19,37,...),比如19是XY(0,2),30是XY(-2,-1)
一个是LAS(层layer>0,扇区area∈[0,5],序号sn∈[0,lay-1]),比如19是LAS(2,5,1),30是LAS(3,3,1)
2)第一步:把两个输入数值分别转换成LAS坐标,再从LAS坐标转成XY坐标
这两个转换可都用数学公式推导出来(提醒:求LAS时可解1元2次方程;求XY时要根据扇区area分别推导)
3)第二步:两个数值的XY向量相减,得到从原点出发的长度向量
4)第三步:从原点出发的长度向量XY坐标,再转回LAS 坐标,最后的“层Layer”即两数距离
主要推导过程和参考实现:
1)LAS坐标
Layer是层数(>0),每一层的起点是 f(layer) = 3*layer*(layer -1)+2,每层有6* layer个数;
如果输入数字a,则a所在的层就是 f(layer) <= a 的最大layer
求解一元二次方程,得到:
参考代码:
2)LAS坐标转XY坐标
参考代码:
3)XY坐标转LAS坐标
参考代码(上面的逆过程):