声明:此系列文章,不是说教,不是告诉任何人如何利用 C++ 开发电子地图的教程,而且本人水平有限,也达不到教程的地步。只是利用此系列的文章,来记录开发基于 C++ 应用在 Windows 下 开发电子地图的过程。愿对 C++ 开发感兴趣的朋友,熟知 Gis 开发的朋友,了解 Wms 、 WFS 协议的朋友,亦或是对 GoogleMap 之类感兴趣的朋友,共同讨论。(废话到此结束)。
计算模块
如果你看这个系列,我想可能你一直在找的就是这部分了。如何实现二分法切割,达到 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 );
}
}
}
}
................................................ 未完待续 ................................................