计算模块
如果你看这个系列,我想可能你一直在找的就是这部分了。如何实现二分法切割,达到Google Map的效果。
此模块是一个纯计算模块。跟以往章节不同,这回我们先不看流程图。先给出两组公式,因为我一直提倡大家自行实现,因为我水平有限,设计的不好,希望大家在掌握原理之后,发挥聪明才智,自行设计。
以下的两组公式,是网络上可以找到又不能找到的,为什么呢?网上给的函数原型是有问题的。我经过验证和使用,修正了这套公式。仅供大家参考。
第一套公式:根据一个经纬度点计算此点处于当前缩放级别中的哪一个瓦块上(x:代表纬线方向上的编号,y:代表经线方向上的编号)。
第二套公式:根据当前缩放级别下指定的瓦块编号,计算出此瓦块左上及右下点的经纬度值。
根据本人的理解,第一套公式用于计算中心瓦块的编号,既用户点击的那个点在当前缩放级别下的瓦块编号,所以只是用一次。重点是第二套公式,人为的按照规律修改瓦块编号,送至此公式中,验证被计算的瓦块的左上或右下点是否在显示范围内的经纬度范围中。如果是,表明这个瓦块要被显示,否则不被显示。如果不很明白,那么请看此模块的设计流程图。
................................................未完待续................................................
如果还是没太明白,那么请看我的实现,我使用回调实现。
首先,将用户点击位置的经纬度值,和当前的缩放级别传入,用来计算这个点所在的瓦块的编号。
void BstarWmsPostOfficeDepot::CalculateXY(TILENUM& segNum)
{
segNum.numX = (int)((180.0 + m_CenterPt.ptx)*pow(2,(double)(17-m_Zoom))/360.0);
double temp1 = pow(2, (double)(17 - m_Zoom));
double temp3 = (45.0 - m_CenterPt.pty/2.0);
double a = tan(temp3*PI/180.0);
double xxx = log(a);
double temp2 = xxx/(2.0*PI);
temp2 = -temp2 + 0.5;
segNum.numY = (int)(temp1*temp2);
}
看来比较乱,主要为了调试时透视个步骤的值,而定义了很多临时变量。TILENUM这个结构体,包含两个int值,分别代表此点在纬线、经线两个方向上的标号。此函数也就是第一套公式的实现。
接下来看看第二套公式的实现,以备后用。
void BstarWmsPostOfficeDepot::GetLatLonFromXY(TILENUM centertile,POINT_D& topPoint,POINT_D& bottomPoint)
{
topPoint.ptx = (double)360.0*centertile.numX/(pow(2, (double)(17 - m_Zoom))) - (double)180.0;
bottomPoint.ptx = (double)360.0*(centertile.numX+1)/(pow(2, (double)(17 - m_Zoom))) - (double)180.0;
double step1 = pow(2, (double)(17 - m_Zoom));
double step2 = (centertile.numY/step1 - 0.5)*2.0*PI;
double step3 = pow(E,step2);
double step4 = atan(step3)*180.0/PI;
bottomPoint.pty = -(45.0 - step4)*2.0;
if (fabs(bottomPoint.pty)<0.000001)
bottomPoint.pty = 0;
step2 = ((centertile.numY+1)/step1 - 0.5)*2.0*PI;
step3 = pow(E,step2);
step4 = atan(step3)*180.0/PI;
topPoint.pty = -(45.0 - step4)*2.0;
if (fabs(topPoint.pty)<0.000001)
topPoint.pty = 0;
}
最后,回调计算将被显示的模块的标号。
首先看调用此回调的位置
void BstarWmsPostOfficeDepot::CalculateTiles(TILENUM centertile, TILES tiles[], int& count)
{
count = 0;
//根据中心点所在图块编号,计算该图块的经纬度范围
POINT_D topPoint,bottomPoint;
GetLatLonFromXY(centertile,topPoint,bottomPoint);
m_tilewidth = bottomPoint.ptx - topPoint.ptx;
m_tileheight = topPoint.pty - bottomPoint.pty;
//将中心点所在瓦片加入到被显示瓦片集中
if (tiles != NULL)
{
m_CenterTileNum.numX = centertile.numX;
m_CenterTileNum.numY = centertile.numY;
tiles[count].index.numX = centertile.numX;
tiles[count].index.numY = centertile.numY;
tiles[count].lefttop = topPoint;
tiles[count].rightbottom = bottomPoint;
}
count++;
//根据中心点经纬度范围计算被显示图块集
RECTLATLON centertileRect;
centertileRect.lefttop = topPoint;
centertileRect.rightbottom = bottomPoint;
centertileRect.leftbottom.ptx = topPoint.ptx;
centertileRect.leftbottom.pty = bottomPoint.pty;
centertileRect.righttop.ptx = bottomPoint.ptx;
centertileRect.righttop.pty = topPoint.pty;
GetOtherTiles(ALL,centertile, centertileRect, tiles, count);
return;
}
再看看回调函数自身的实现
void BstarWmsPostOfficeDepot::GetOtherTiles(int NotWay,TILENUM centertile, RECTLATLON centertileRect, TILES tiles[], int& count)
{
if (count >= MAX_TILE_COUNT)
{
return;
}
TILENUM tilenum;
POINT_D topPoint,bottomPoint;
RECTLATLON Toprect,Rightrect,Bottomrect,Leftrect;
//计算上
if(UP != NotWay)
{
if (count >= MAX_TILE_COUNT)
{
return;
}
tilenum.numX = centertile.numX;
tilenum.numY = centertile.numY + 1;
GetLatLonFromXY(tilenum,topPoint,bottomPoint);
Toprect.lefttop = topPoint;
Toprect.rightbottom = bottomPoint;
Toprect.leftbottom.ptx = topPoint.ptx;
Toprect.leftbottom.pty = bottomPoint.pty;
Toprect.righttop.ptx = bottomPoint. ptx;
Toprect.righttop.pty = topPoint.pty;
if (IsInRect(Toprect.leftbottom,TotalRect)||
IsInRect(Toprect.rightbottom,TotalRect))
{
if (IsValidPt(topPoint)&&IsValidPt(bottomPoint)&&(!IsExisted(tilenum,count)))
{
if (tiles != NULL)
{
tiles[count].index.numX = tilenum.numX;
tiles[count].index.numY = tilenum.numY;
tiles[count].lefttop = topPoint;
tiles[count].rightbottom = bottomPoint;
}
count++;
GetOtherTiles(DOWN,tilenum, Toprect, tiles, count);
}
}
}
//计算右
if(RIGHT != NotWay)
{
if (count >= MAX_TILE_COUNT)
{
return;
}
tilenum.numX = centertile.numX + 1;
tilenum.numY = centertile.numY;
GetLatLonFromXY(tilenum,topPoint,bottomPoint);
Rightrect.lefttop = topPoint;
Rightrect.rightbottom = bottomPoint;
Rightrect.leftbottom.ptx = topPoint.ptx;
Rightrect.leftbottom.pty = bottomPoint.pty;
Rightrect.righttop.ptx = bottomPoint. ptx;
Rightrect.righttop.pty = topPoint.pty;
if (IsInRect(Rightrect.lefttop,TotalRect)||
IsInRect(Rightrect.leftbottom,TotalRect))
{
if (IsValidPt(topPoint)&&IsValidPt(bottomPoint)&&(!IsExisted(tilenum,count)))
{
if (tiles != NULL)
{
tiles[count].index.numX = tilenum.numX;
tiles[count].index.numY = tilenum.numY;
tiles[count].lefttop = topPoint;
tiles[count].rightbottom = bottomPoint;
}
count++;
GetOtherTiles(LEFT,tilenum, Rightrect, tiles, count);
}
}
}
//计算下
if(DOWN != NotWay)
{
if (count >= MAX_TILE_COUNT)
{
return;
}
tilenum.numX = centertile.numX;
tilenum.numY = centertile.numY - 1;
GetLatLonFromXY(tilenum,topPoint,bottomPoint);
Bottomrect.lefttop = topPoint;
Bottomrect.rightbottom = bottomPoint;
Bottomrect.leftbottom.ptx = topPoint.ptx;
Bottomrect.leftbottom.pty = bottomPoint.pty;
Bottomrect.righttop.ptx = bottomPoint. ptx;
Bottomrect.righttop.pty = topPoint.pty;
if (IsInRect(Bottomrect.lefttop,TotalRect)||
IsInRect(Bottomrect.righttop,TotalRect))
{
if (IsValidPt(topPoint)&&IsValidPt(bottomPoint)&&(!IsExisted(tilenum,count)))
{
if (tiles != NULL)
{
tiles[count].index.numX = tilenum.numX;
tiles[count].index.numY = tilenum.numY;
tiles[count].lefttop = topPoint;
tiles[count].rightbottom = bottomPoint;
}
count++;
GetOtherTiles(UP,tilenum, Bottomrect, tiles, count);
}
}
}
//计算左
if(LEFT != NotWay)
{
if (count >= MAX_TILE_COUNT)
{
return;
}
tilenum.numX = centertile.numX - 1;
tilenum.numY = centertile.numY;
GetLatLonFromXY(tilenum,topPoint,bottomPoint);
Leftrect.lefttop = topPoint;
Leftrect.rightbottom = bottomPoint;
Leftrect.leftbottom.ptx = topPoint.ptx;
Leftrect.leftbottom.pty = bottomPoint.pty;
Leftrect.righttop.ptx = bottomPoint. ptx;
Leftrect.righttop.pty = topPoint.pty;
if (IsInRect(Leftrect.righttop,TotalRect)||
IsInRect(Leftrect.rightbottom,TotalRect))
{
if (IsValidPt(topPoint)&&IsValidPt(bottomPoint)&&(!IsExisted(tilenum,count)))
{
if (tiles != NULL)
{
tiles[count].index.numX = tilenum.numX;
tiles[count].index.numY = tilenum.numY;
tiles[count].lefttop = topPoint;
tiles[count].rightbottom = bottomPoint;
}
count++;
GetOtherTiles(RIGHT,tilenum, Leftrect, tiles, count);
}
}
}
}
................................................未完待续................................................