栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

基于瓦片的热力图生成(Qt |C++)

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

基于瓦片的热力图生成(Qt |C++)

目录

前言

一、整体思路

二、实现步骤

1.主要代码

2.具体效果

 总结


前言

最近接触到一个项目,就是根据导入的矢量点文件以瓦片渲染的方式生成热力图。


一、整体思路

当地图请求某张瓦片时,根据瓦片范围查询矢量文件在该范围的点,再用点的经纬度计算出该点在这张瓦片上的像素坐标,以该像素坐标用alpha通道绘制渐变圆,其余地方以alpha=0进行填充,此时得到的是一张灰度图像,再根据alpha值映射到一条色带上进行赋色,即可得到热力图像。

二、实现步骤

1.主要代码

代码如下(示例):

E_QUERY_RESULT CGDALHeatmapFieldDataSource::QueryImage(QImage& rImage, const CTileKey& rTileKey) const
{
	CTileKey tileKey = rTileKey; //当前瓦片
    //设置当前瓦片的投影
	E_TILE_MODEL eTileModel = tileKey.GetTileModel();
	switch(eTileModel)
	{
	case E_TILE_MODEL_ACMAP:
		{
			bool bWGS84 = Tools::isWGS(m_eMapType);
			if (bWGS84)
			{
				eTileModel = E_TILE_MODEL_WGS84;
			}
			else
			{
				eTileModel = E_TILE_MODEL_MERCATOR;

			}
		}
		break;
	case E_TILE_MODEL_MERCATOR:
		{

		}
		break;
	case E_TILE_MODEL_WGS84:
		{

		}
		break;
	}
	CTileModel* ptileModel = ITileModel::GetTileModel(eTileModel);
	if (ptileModel == NULL)
	{
		return E_QUERY_RESULT_NODATA;
	}
	tileKey.ChangeTileModel(eTileModel);
	EXTENT rExtent = ptileModel->GetGeoExtent(tileKey);
    //瓦片坐上角坐标转像素坐标
	int nTilePixelX;
	int nTilePixelY;
	ptileModel->GetPixelCoordinate(nTilePixelX, nTilePixelY, rTileKey);
    //用一张瓦片大小的图片把alpha通道填充为全0
	QImage img(256,256,QImage::Format_Alpha8);
	img.fill(Qt::transparent);
	img.fill(QColor(0,0,0,0));
	QPainter painter(&img);
	//painter.save();
    //把瓦片左上角像素坐标转为世界坐标即整个地图左上角
	painter.translate(-nTilePixelX, -nTilePixelY);
	double dPixelX = 0;
	double dPixelY = 0;
	for (int i=0; iGetPixelViaGeo(dPixelX, dPixelY, tileKey.GetLevel(), m_vec3D.at(i).x, m_vec3D.at(i).y);
        //设置渐变
		QRadialGradient gradient(dPixelX, dPixelY, m_nRadius);//设置渐变模式为径向m_nRadius为渐变半径
        //考虑是否加权两种情况,不加劝最大透明度即为当前设置的透明度,否则为加权后的透明度
		if(m_fieldName == "NULL" || m_vecAlphaValue.empty())
		{
			gradient.setColorAt(0, QColor(0, 0, 0, nMaxAlphaValue));//设置圆心为最大透明度(nMaxAlphaValue)
		}
		else
		{
			gradient.setColorAt(0, QColor(0, 0, 0, m_vecAlphaValue.at(i)));//设置圆心为最大透明度(m_vecAlphaValue.at(i))
		}
		gradient.setColorAt(1, QColor(0, 0, 0, 0));
		painter.setPen(Qt::NoPen);
		painter.setBrush(gradient);
        //抗锯齿效果
		painter.setRenderHint(QPainter::HighQualityAntialiasing);
        //绘制渐变圆
		painter.drawEllipse(QPoint(dPixelX, dPixelY), m_nRadius, m_nRadius);
		//painter.save();
		//painter.restore();
	}
    //因为没有色带接口,该块主要用于自定义一个渐变色带
	QLinearGradient gradientLine(0, 0, nMaxAlphaValue+1, 1);
    //保证色带最大值始终对应设置的alpha最大值
	QImage imgCanvas(nMaxAlphaValue+1, 1, QImage::Format_RGBA8888);
	gradientLine.setColorAt(0.45, Qt::blue);
	gradientLine.setColorAt(0.55, Qt::cyan);
	gradientLine.setColorAt(0.65, Qt::green);
	gradientLine.setColorAt(0.85, Qt::yellow);
	gradientLine.setColorAt(1.0, Qt::red);
	QPainter painter1(&imgCanvas);
	painter1.setBrush(gradientLine);
	painter1.setPen(Qt::NoPen);
	painter1.fillRect(imgCanvas.rect(), gradientLine);

	//像素转换把灰度图转换为有颜色的图像
	int alpha = 0;
	int finalAlpha = 0;
	QColor color;
	QImage img1(NUM_DEFAULT_PIXEL_SIZE, NUM_DEFAULT_PIXEL_SIZE, QImage::Format_RGBA8888);//NUM_DEFAULT_PIXEL_SIZE = 256
	for (int i = 0; i < 256; ++i) 
	{
		for (int j = 0; j < 256; ++j) 
		{
			alpha = qAlpha(img.pixel(i, j));
            //alpha等于0即为透明还是设为透明
			if (!alpha)
			{
				img1.setPixel(i, j, qRgba(0,
					0,
					0,
					0));
				continue;
			}
            //因为存在渐变圆透明度叠加,需保证透明度不超过设置的最大值				
			finalAlpha = (alpha < nMaxAlphaValue ? alpha : nMaxAlphaValue);
            //根据透明度从自定义色带取对应的值进行赋色
			color = imgCanvas.pixel(finalAlpha,0.5);
			img1.setPixel(i, j, qRgba(color.red(),
				color.green(),
				color.blue(),
				finalAlpha));
		}
	}

	rImage = img1;
	//}
	
	return E_QUERY_RESULT_VALID;
}

2.具体效果

不加权:

加权: 

更改渲染半径:

更改透明度:


 总结

分享结束!

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/950350.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号