C++地图下载器:支持多线程下载不同数据源卫星影像、街道路网、地形、海洋、高程瓦片Tile数据

1、功能概述

  卫星地图影像Tile下载器,详细功能包括如下几点:

  • 1、简洁界面,操作明了;MFC界面,可以快速修改为Qt界面;
  • 2、可以依据配置下载各类卫星影像、街道路网、地形、海洋、高程的瓦片Tile数据;
  • 3、默认下载ArcGis,可通过配置支持天地图、谷歌、高德、百度等地图源;
  • 4、支持多线程下载,进度条显示实时进度和下载时间;
  • 5、支持将各级别Tile瓦片进行拼接形成大图,1000张小图拼接为1张大图,速度大约2秒;
  • 6、支持预览各级别影像图片;
  • 7、简单美化界面后可以作为课程设计或大作业进行提交。

在这里插入图片描述

2、功能介绍

在这里插入图片描述

2.1 地图资源

  不同的地图源都有其对应的瓦片Tile下载地址,下面以ArcGIS举例说明:

	//卫星影像
	https://services.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/0/0/0.jpg;
	//街道路网
	https://services.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer/tile/;
	//地形
	https://server.arcgisonline.com/ArcGIS/rest/services/World_Physical_Map/MapServer/tile/;
	//海洋
	ttps://server.arcgisonline.com/ArcGIS/rest/services/Ocean/World_Ocean_Base/MapServer/tile/;
	//山影
	https://services.arcgisonline.com/arcgis/rest/services/Elevation/World_Hillshade/MapServer/tile/;

2.2 瓦片下载

  地图源对应的瓦片Tile下载地址可以直接在浏览器打开为图片,因此我们仅需要利用工具把它保存下来即可,此处采用的是libcurl库,由于下载链接为https,因此libcurl库的编译版本需要支持openssl加密,源码中已经附带了编译好的libcurl库,可以直接使用。如果采用不支持openssl的库,会出现图片无法下载的错误。下载功能比较简单:

size_t write_data(char* buffer, size_t size, size_t nitems, void* outstream)
{
	size_t written = fwrite(buffer, size, nitems, (FILE*)outstream);
	return written;
}

	CURL* pCurl;
	pCurl = curl_easy_init();
	FILE* pFile = nullptr;
	fopen_s(&pFile, sFilePath.c_str(), "wb");
	curl_easy_setopt(pCurl, CURLOPT_SSL_VERIFYPEER, FALSE);
	curl_easy_setopt(pCurl, CURLOPT_SSL_VERIFYHOST, FALSE);
	curl_easy_setopt(pCurl, CURLOPT_WRITEDATA, (void*)pFile);
	curl_easy_setopt(pCurl, CURLOPT_WRITEFUNCTION, write_data);
	curl_easy_setopt(pCurl, CURLOPT_URL, sUrl.c_str());
	CURLcode resCode = curl_easy_perform(pCurl);
	fclose(pFile);

2.3 自定义进度条

  MFC提供的进度条比较不美观。如果用Qt的话不用自己重绘进度条。既然用MFC了,就顺手美化一下进度条吧。

void CMyProgressCtrl::OnPaint() 
{
	CPaintDC dc(this); // device context for painting

	// TODO: Add your message handler code here
	CRect cRect;
	GetClientRect(cRect);

	CString sPos;
	int nLower,nUpper;
	CRect rcRange = cRect;

	GetRange(nLower,nUpper);
	if(nUpper - nLower > 0)
	{
		sPos.Format(_T("%d%%"),100*GetPos()/(nUpper-nLower) );
		rcRange.right = (int)(rcRange.left + rcRange.Width() * (double)GetPos()/(nUpper-nLower));
	}
	else
	{
		sPos = "0%";
		dc.FillSolidRect(cRect, GetSysColor(COLOR_3DFACE));
		dc.Draw3dRect(cRect, RGB(0,0,0), RGB(0,0,0));
		dc.SetBkMode(TRANSPARENT);
		dc.DrawText(sPos, cRect, DT_CENTER);
		return;
	}

	CDC memDC,memDC2;
	CBitmap bmp,bmp2;

	bmp.CreateCompatibleBitmap(&dc,cRect.Width(),cRect.Height());
	memDC.CreateCompatibleDC(&dc);
	memDC.SelectObject(&bmp);

	bmp2.CreateCompatibleBitmap(&dc,cRect.Width(),cRect.Height());
	memDC2.CreateCompatibleDC(&dc);
	memDC2.SelectObject(&bmp2);

	memDC2.FillSolidRect(cRect, RGB(255,0,0));	//底色用RGB(255,0,0)
	memDC2.FillSolidRect(rcRange, RGB(0,255,255));	//已完成的进度用RGB(0,255,255)填充

	memDC.FillSolidRect(cRect, RGB(0,0,0));
	memDC.SetBkMode(TRANSPARENT);
	memDC.SetTextColor(RGB(255,0,0));
	memDC.DrawText(sPos, cRect, DT_CENTER|DT_VCENTER|DT_SINGLELINE);		//memDC中现在是黑底红字

	//SRCPAINT是OR操作, 所以现在memDC2中, 落在已完成进度区域内的字是白色(0|255, 255|255, 255|255), 落在未完成区域内的字和底色融为一体了(255|255, 0|0, 0|0)。
	memDC2.BitBlt(0, 0, cRect.Width(), cRect.Height(), &memDC, 0, 0, SRCPAINT);	

	memDC.FillSolidRect(cRect, RGB(255,0,0));

	//把已完成部分的底色RGB(0,255,255)设为透明色,现在memDC中只剩下红底白字了。
	//memDC.TransparentBlt(0,0,cRect.Width(),cRect.Height(),&memDC2,0,0,cRect.Width(),cRect.Height(),RGB(0,255,255));
	TransparentBlt(memDC.m_hDC,0,0,cRect.Width(),cRect.Height(),memDC2.m_hDC,0,0,cRect.Width(),cRect.Height(),RGB(0,255,255));

	memDC2.FillSolidRect(cRect, GetSysColor(COLOR_3DFACE));
	memDC2.SetBkMode(TRANSPARENT);
	memDC2.SetTextColor(RGB(0,0,0));
	memDC2.DrawText(sPos, cRect, DT_CENTER|DT_VCENTER|DT_SINGLELINE);	//用黑色绘制文字

	//绘制已完成进度的进度条,完成后覆盖了已完成区域内的黑色文字
	for(int i=rcRange.top; i<rcRange.bottom; i++)
	{
		CPen pen, *pOldPen;
		pen.CreatePen(PS_SOLID, 1, GetColor(i-rcRange.top, rcRange.Height()));
		pOldPen = memDC2.SelectObject(&pen);

		memDC2.MoveTo(rcRange.left, i);
		memDC2.LineTo(rcRange.right, i);

		memDC2.SelectObject(pOldPen);
	}

	//把memDC中的白字部分叠加到memDC2中,完成进度条绘制。	
	//memDC2.TransparentBlt(0,0,cRect.Width(),cRect.Height(),&memDC,0,0,cRect.Width(),cRect.Height(),RGB(255,0,0));
	TransparentBlt(memDC2.m_hDC,0,0,cRect.Width(),cRect.Height(),memDC.m_hDC,0,0,cRect.Width(),cRect.Height(),RGB(255,0,0));

	memDC2.Draw3dRect(0, 0, cRect.Width(), cRect.Height(), RGB(0,0,0), RGB(0,0,0));
	dc.BitBlt(0,0,cRect.Width(),cRect.Height(),&memDC2,0,0,SRCCOPY);

	memDC2.DeleteDC();
	memDC.DeleteDC();
	bmp.DeleteObject();
	bmp2.DeleteObject();

	// Do not call CProgressCtrl::OnPaint() for painting messages
}

2.4 加载影像

  MFC提供的pictureCtrl控件可以直接加载图片,不过要用到CImage类。CImage类的具体用法可以参考另一篇博客:图像处理必须要用OpenCV 吗? ??试一下CImage类像素级处理图像:复制、截屏、拼接、裁剪、缩放、灰度图!

CDC* pdc = GetDlgItem(IDC_STATIC_MAP)->GetWindowDC();
CRect rect;
GetDlgItem(IDC_STATIC_MAP)->GetClientRect(&rect);
CImage image;
image.Load(strCacheFile);
image.Draw(pdc->m_hDC, rect);

CString strShowLevel;
strShowLevel.Format(_T("显示等级:%d"), 0);
GetDlgItem(IDC_STATIC_SHOWLEVEL)->SetWindowText(strShowLevel);

2.5 拼接瓦片

  瓦片数据被分为一片片,预览时候需要拼成一张大图来进行加载,因此需要实现图片拼接功能。利用CImage类可以将图片进行拼接。具体拼接顺序和方式可以依据需要自己进行调整。具体用法可以参考另一篇博客:图像处理必须要用OpenCV 吗? ??试一下CImage类像素级处理图像:复制、截屏、拼接、裁剪、缩放、灰度图!

	int nHeight = nCount * 256;
	int nWidth = nCount * 256;
	CImage imageDest;
	imageDest.Create(nWidth, nHeight, 24);
	HDC hDCImgDest = imageDest.GetDC();

	for (int i = 0; i < vecTiles.size(); i++)
	{
		CString strImagePath = vecTiles.at(i).strFilePath;
		int nX = vecTiles.at(i).nX;
		int nY = vecTiles.at(i).nY;

		CImage imageOrign;
		HRESULT hResult = imageOrign.Load(strImagePath);
		BitBlt(hDCImgDest, nX, nY, 256, 256, imageOrign.GetDC(), 0, 0, SRCCOPY);
		imageOrign.ReleaseDC();
	}
	imageDest.ReleaseDC();

	HRESULT hRes = S_FALSE;
	hRes = imageDest.Save(strOutputPath);
	if (!SUCCEEDED(hRes))
	{
		MessageBox(_T("合并图像文件失败!"));
	}

3、源码下载地址

源码下载:https://download.csdn.net/download/m0_37251750/89632711

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

欧特克_Glodon

很高兴能帮助到您!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值