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

6 篇文章 0 订阅

目录

前言

一、整体思路

二、实现步骤

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; i<m_vec3D.size(); i++)
	{
        //计算出处于当前瓦片内的矢量点集对应的像素坐标(世界坐标)
		ptileModel->GetPixelViaGeo(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;
	//}
	/*if (!rImage.isNull())
	{
		std::stringstream ss;
		ss << "D:/SGDownload/" << rTileKey.GetTileKeyString() << ".png";
		rImage.save(ConvertStdStringToQString(ss.str()), "png", -1);
	}*/
	return E_QUERY_RESULT_VALID;
}

2.具体效果

不加权:

加权: 

更改渲染半径:

更改透明度:


 总结

分享结束!

  • 10
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值